/*
 * Package il.ac.biu.cs.grossmm.api.data
 * File XmlPropertyMapping.java
 * 
 * This is a part of presence service framework API. 
 * See javadoc for more information.
 *  
 * Copyright (C) 2006 Grossmann Mark
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package il.ac.biu.cs.grossmm.api.data;

import java.util.HashMap;

public class XmlPropertyMapping<N, V> implements XmlValueMapping<V> {
	private final Property<N, V> property;
	private final XmlValueMapping<V> xmlValueMapping;
	
	
	public Class<V> getValueClass()
	{
		return xmlValueMapping.getValueClass();
	}
	
	public String toString(V value) throws Exception
	{
		return xmlValueMapping.toString(value);
	}
	
	public V valueOf(String str) throws Exception
	{
		return xmlValueMapping.valueOf(str);
	}
	
	public int index() {
		return property.index();
	}
	
	
	/**
	 * @param valueClass
	 * @param property
	 * @param xmlValueMapping
	 */
	public XmlPropertyMapping(Property<N, V> property)
	{
		this.property = property;
		this.xmlValueMapping = xmlMapping(property.getValueClass());
	}
	/**
	 * @param valueClass
	 * @param property
	 * @param xmlValueMapping
	 */
	public XmlPropertyMapping(Property<N, V> property, XmlValueMapping<V> xmlValueMapping, Pair<V, String>...map)
	{
		this.property = property;
		this.xmlValueMapping = xmlMapping(property.getValueClass(), map);
	}
		
	public static final XmlValueMapping<String> STRING =
		new StringMapping();

	public static final XmlValueMapping<Integer> INTEGER =
		new IntegerMapping();

	public static final XmlValueMapping<Float> FLOAT = new FloatMapping();

	public static final XmlValueMapping<Double> DOUBLE =
		new DoubleMapping();

	public static final XmlValueMapping<Boolean> BOOLEAN =
		new BooleanMapping();

	@SuppressWarnings("unchecked")
	public static <V> XmlValueMapping<V> xmlMapping(Class<V> valueClass)
	{
		if (valueClass.equals(String.class))
			return (XmlValueMapping<V>) STRING;

		if (valueClass.equals(Integer.class))
			return (XmlValueMapping<V>) INTEGER;

		if (valueClass.equals(Float.class))
			return (XmlValueMapping<V>) FLOAT;

		if (valueClass.equals(Double.class))
			return (XmlValueMapping<V>) DOUBLE;

		if (valueClass.equals(Boolean.class))
			return (XmlValueMapping<V>) BOOLEAN;

		throw new RuntimeException("Unsuppored xml mapping for " + valueClass);

	}

	public static <V> XmlValueMapping<V> xmlMapping(Class<V> valueClass,
		Pair<V, String>... map)
	{
		return new CustomMapping<V>(valueClass, map);
	}

	protected static class StringMapping implements XmlValueMapping<String> {

		public String valueOf(String str) throws Exception
		{
			return str;
		}

		public String toString(String value) throws Exception
		{
			return value;
		}

		public Class<String> getValueClass()
		{
			return String.class;
		}
	}

	protected static class IntegerMapping implements XmlValueMapping<Integer> {

		public Integer valueOf(String str) throws Exception
		{
			return Integer.valueOf(str);
		}

		public String toString(Integer value) throws Exception
		{
			return value.toString();
		}

		public Class<Integer> getValueClass()
		{
			return Integer.class;
		}
	}

	protected static class FloatMapping implements XmlValueMapping<Float> {
		public Float valueOf(String str) throws Exception
		{
			return Float.valueOf(str);
		}

		public String toString(Float value) throws Exception
		{
			return value.toString();
		}

		public Class<Float> getValueClass()
		{
			return Float.class;
		}
	}

	protected static class DoubleMapping implements XmlValueMapping<Double> {
		public Double valueOf(String str) throws Exception
		{
			return Double.valueOf(str);
		}

		public String toString(Double value) throws Exception
		{
			return value.toString();
		}

		public Class<Double> getValueClass()
		{
			return Double.class;
		}
	}

	protected static class BooleanMapping implements XmlValueMapping<Boolean> {
		public Boolean valueOf(String str) throws Exception
		{
			return Boolean.valueOf(str);
		}

		public String toString(Boolean value) throws Exception
		{
			return value.toString();
		}

		public Class<Boolean> getValueClass()
		{
			return Boolean.class;
		}
	}

	protected static class CustomMapping<V> implements XmlValueMapping<V> {
		final HashMap<String, V> stv;

		final HashMap<V, String> vts;
		
		final Class<V> valueClass;

		public CustomMapping(Class<V> valueClass, Pair<V, String>... map)
		{
			this.valueClass = valueClass;
			
			int len = map.length;
			this.stv = new HashMap<String, V>(len);
			this.vts = new HashMap<V, String>(len);

			for (Pair<V, String> vs : map) {
				vts.put(vs.first(), vs.second());
				stv.put(vs.second(), vs.first());
			}
		}

		public V valueOf(String str) throws Exception
		{
			return stv.get(str);
		}

		public String toString(V value) throws Exception
		{
			return vts.get(value);
		}

		public Class<V> getValueClass()
		{
			return valueClass;
		}
	}
}	
